/**    
 * 文件名：CRCUtil.java<br/>
 * 版本信息：<br/>    
 * 日期：2014-8-19<br/>    
 * Copyright www.szholly.com 2014 版权所有<br/>     
 */
package com.hrt.datasender.process.strategy.hj212.util;

import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;

/**
 * 项目名称：SludgeMonitor<br/>
 * 类名称：CRCUtil<br/>
 * 类描述：CRC校验工具类<br/>
 * 修改人：Thyne.Tang(TangHui@szholly.com)<br/>
 * 修改时间：2014-8-19 下午6:58:30<br/>
 * 修改备注：
 * 
 * @author Thyne.Tang(TangHui@szholly.com)
 * @since 2014-8-19 下午6:58:30
 * @version 1.0
 */
public class CRCUtil {
    // 多项式1010 0000 0000 0001的十六进制
    private static final int MULTITERM = 0xA001;
    
    // 1.装入一值全是“1”的16位寄存器
    private static final int MASKCODEFFFF = 0xFFFF;
    
    private static final int CRCLENGTH = 4;
    
    private static final int MSGPREFIXLENGTH = 6;
    
    private static final int SHIFTBIT8 = 8;

    /**
     * 生成CRC校验码<br>
     * 算法说明<br>s
     * 1:装入一值全是“1”的16位寄存器。<br>
     * 2.取被检验串的一个字节与16位寄存器的高位字节进行异或运算， 运算结果放入这个16位寄存器。<br>
     * 3.把16位寄存器向右移一位。<br>
     * 4.若向右移出的数位是1，则生成多项式1010 0000 0000 0001和这个 寄存器进行异或运算，若向右移出的数位是0则返回(3)。<br>
     * 5.重复(3)和(4)，直至移出8位。<br>
     * 6.取被检验的下一个字节。<br>
     * 7.重复(2)-(6)直至被检验的所有字节均与16位寄存器进行异或运算， 并移位8次。<br>
     * 8.这个寄存器的内容即为两个字节的检验码。 检验码按先高字节后低字节的顺序存放。
     **/
    public static String calcCRC(String strData) {
        
        int uCRC = MASKCODEFFFF;
        
        // 字节数组
        byte[] dataArray = null;
        // 判断字符串数据不为空
        if (strData != null && !"".equals(strData)) {
            // 字符串数据转为字节数组
            try {
                dataArray = strData.getBytes("ASCII");
            } 
            catch (UnsupportedEncodingException e) {
                return null;
            }
            // 7.重复(2)-(6)直至被检验的所有字节均与16位寄存器进行异或运算
            for (int i = 0; i < dataArray.length; i++) {
                // 2.取被检验串的一个字节与16位寄存器的高位字节进行异或运算,运算结果放入这个16位寄存器
                uCRC = (int) (dataArray[i] ^ (uCRC >> SHIFTBIT8));
                // 5.重复(3)和(4)，直至移出8位
                for (int j = 0; j < SHIFTBIT8; j++) {
                    // 4.若向右移出的数位是1，则生成多项式1010 0000 0000
                    // 0001和这个寄存器进行异或运算，若向右移出的数位是0则返回3.
                    if ((uCRC & 0x0001) == 1) {
                        // 3.把16位寄存器向右移一位
                        uCRC >>= 1;
                        uCRC ^= MULTITERM;
                        continue;
                    }
                    // 3.把16位寄存器向右移一位
                    uCRC >>= 1;
                }
            }
        }
        return StringUtils.leftPad(Integer.toHexString(uCRC).toUpperCase(), CRCLENGTH, "0");
    }

    public static String calcCRCHoldData(String msg) {
        int msgLength = msg.length();
        String realMsg = "";
        if (realMsg.endsWith("&&")) {
            realMsg = msg;
        }
        else {
            realMsg = msg.substring(MSGPREFIXLENGTH, msgLength - CRCLENGTH);
        }
        String r1 = CRCUtil.calcCRC(realMsg);
        return r1;
    }

    public static boolean match(String msg) {
        int msgLength = msg.length();
        String crc = msg.substring(msgLength - CRCLENGTH, msgLength);
        String r1 = CRCUtil.calcCRCHoldData(msg);
        boolean result = crc.equals(r1);
        return result;
    }

    public static void main(String[] args) throws Exception {
        String testStr = "01-Flag=N;029-Rtd=0.003,029-Flag=N;028-Rtd=0.000,028-Flag=N;060-Rtd=0.007,060-Flag=N;101-Rtd=0.204,101-Flag=N;023-Rtd=0.020,023-Flag=N;065-Rtd=5.480,065-Flag=N;011-Rtd=5.405,011-Flag=N&&";
        testStr = "02;10N;011-Rtd=1.769,011-Flag=N;023-Rtd=0.011,023-Flag=N;060-Rtd=0.002,060-Flag=N&&";
        String r1 = CRCUtil.calcCRC(testStr);
        System.out.println("CRC16 = " + r1);
        System.out.println("9E81".equals(r1));
    }
}
